package com.ruoyi.project.dj.utils;

import com.ruoyi.common.utils.security.ShiroUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import com.ruoyi.project.dj.service.IDjStudyRecordService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 学习时长记录工具类
 * 提供通用的学习时长记录功能，支持多种资源类型
 * 
 * @author ruoyi
 * @date 2025-09-25
 */
public class StudyTimeRecorder {
    
    private static final Logger log = LoggerFactory.getLogger(StudyTimeRecorder.class);
    
    /**
     * 资源类型常量
     */
    public static final String TYPE_VIDEO = "video";        // 视频
    public static final String TYPE_MATERIAL = "material";  // 材料
    public static final String TYPE_AUDIO = "audio";        // 有声读物
    public static final String TYPE_BOOK = "book";          // 红色书籍
    public static final String TYPE_REALTIME = "realtime";  // 实时资料
    
    /**
     * 学习会话存储
     * Key: memberId_resourceType_resourceId
     * Value: StudySession
     */
    private static final ConcurrentHashMap<String, StudySession> sessions = new ConcurrentHashMap<>();
    
    /**
     * 定时任务执行器，用于定期保存学习进度
     */
    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);
    
    /**
     * 默认保存间隔（秒）
     */
    private static final int DEFAULT_SAVE_INTERVAL = 30;
    
    /**
     * 学习会话内部类
     */
    private static class StudySession {
        private Long memberId;
        private String resourceType;
        private Long resourceId;
        private long startTime;
        private long lastSaveTime;
        private int totalDuration;  // 累计学习时长（秒）
        private Integer currentPosition; // 当前位置（秒）
        
        public StudySession(Long memberId, String resourceType, Long resourceId) {
            this.memberId = memberId;
            this.resourceType = resourceType;
            this.resourceId = resourceId;
            this.startTime = System.currentTimeMillis();
            this.lastSaveTime = this.startTime;
            this.totalDuration = 0;
        }
        
        /**
         * 计算从上次保存到现在的学习时长
         */
        public int getDurationSinceLastSave() {
            long currentTime = System.currentTimeMillis();
            int duration = (int) ((currentTime - lastSaveTime) / 1000);
            lastSaveTime = currentTime;
            totalDuration += duration;
            return duration;
        }
        
        /**
         * 获取总学习时长
         */
        public int getTotalDuration() {
            long currentTime = System.currentTimeMillis();
            return totalDuration + (int) ((currentTime - lastSaveTime) / 1000);
        }
        
        // Getters and Setters
        public Long getMemberId() { return memberId; }
        public String getResourceType() { return resourceType; }
        public Long getResourceId() { return resourceId; }
        public Integer getCurrentPosition() { return currentPosition; }
        public void setCurrentPosition(Integer currentPosition) { this.currentPosition = currentPosition; }
    }
    
    /**
     * 开始学习记录
     * 
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     */
    public static void startStudy(String resourceType, Long resourceId) {
        try {
            Long memberId = ShiroUtils.getUserId();
            if (memberId == null) {
                log.warn("用户未登录，无法记录学习时长");
                return;
            }
            
            startStudy(memberId, resourceType, resourceId);
        } catch (Exception e) {
            log.error("开始学习记录失败", e);
        }
    }
    
    /**
     * 开始学习记录
     * 
     * @param memberId 党员ID
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     */
    public static void startStudy(Long memberId, String resourceType, Long resourceId) {
        try {
            String sessionKey = buildSessionKey(memberId, resourceType, resourceId);
            
            // 检查是否已存在会话
            if (sessions.containsKey(sessionKey)) {
                log.info("学习会话已存在: {}", sessionKey);
                return;
            }
            
            // 创建新的学习会话
            StudySession session = new StudySession(memberId, resourceType, resourceId);
            sessions.put(sessionKey, session);
            
            // 初始化数据库记录
            IDjStudyRecordService studyRecordService = SpringUtils.getBean(IDjStudyRecordService.class);
            studyRecordService.startStudyRecord(memberId, resourceType, resourceId);
            
            // 启动定时保存任务
            startAutoSaveTask(sessionKey);
            
            log.info("开始学习记录: 用户{}, 资源类型{}, 资源ID{}", memberId, resourceType, resourceId);
            
        } catch (Exception e) {
            log.error("开始学习记录失败", e);
        }
    }
    
    /**
     * 更新学习位置（主要用于视频、音频等媒体资源）
     * 
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     * @param position 当前位置（秒）
     */
    public static void updatePosition(String resourceType, Long resourceId, Integer position) {
        try {
            Long memberId = ShiroUtils.getUserId();
            if (memberId == null) {
                return;
            }
            
            updatePosition(memberId, resourceType, resourceId, position);
        } catch (Exception e) {
            log.error("更新学习位置失败", e);
        }
    }
    
    /**
     * 更新学习位置
     * 
     * @param memberId 党员ID
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     * @param position 当前位置（秒）
     */
    public static void updatePosition(Long memberId, String resourceType, Long resourceId, Integer position) {
        try {
            String sessionKey = buildSessionKey(memberId, resourceType, resourceId);
            StudySession session = sessions.get(sessionKey);
            
            if (session != null) {
                session.setCurrentPosition(position);
            }
        } catch (Exception e) {
            log.error("更新学习位置失败", e);
        }
    }
    
    /**
     * 结束学习记录
     * 
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     */
    public static void endStudy(String resourceType, Long resourceId) {
        try {
            Long memberId = ShiroUtils.getUserId();
            if (memberId == null) {
                return;
            }
            
            endStudy(memberId, resourceType, resourceId, false);
        } catch (Exception e) {
            log.error("结束学习记录失败", e);
        }
    }
    
    /**
     * 结束学习记录
     * 
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     * @param isComplete 是否完成学习
     */
    public static void endStudy(String resourceType, Long resourceId, boolean isComplete) {
        try {
            Long memberId = ShiroUtils.getUserId();
            if (memberId == null) {
                return;
            }
            
            endStudy(memberId, resourceType, resourceId, isComplete);
        } catch (Exception e) {
            log.error("结束学习记录失败", e);
        }
    }
    
    /**
     * 结束学习记录
     * 
     * @param memberId 党员ID
     * @param resourceType 资源类型
     * @param resourceId 资源ID
     * @param isComplete 是否完成学习
     */
    public static void endStudy(Long memberId, String resourceType, Long resourceId, boolean isComplete) {
        try {
            String sessionKey = buildSessionKey(memberId, resourceType, resourceId);
            StudySession session = sessions.remove(sessionKey);
            
            IDjStudyRecordService studyRecordService = SpringUtils.getBean(IDjStudyRecordService.class);
            
            if (session != null) {
                // 有活跃会话，使用会话数据进行最后一次保存
                int finalDuration = session.getTotalDuration();
                studyRecordService.endStudyRecord(memberId, resourceType, resourceId, 
                                                  finalDuration, session.getCurrentPosition(), isComplete);
                
                log.info("结束学习记录(有会话): 用户{}, 资源类型{}, 资源ID{}, 总时长{}秒, 完成状态{}", 
                         memberId, resourceType, resourceId, finalDuration, isComplete);
            } else {
                // 没有活跃会话，但仍然尝试更新数据库记录的完成状态
                log.warn("结束学习记录时未找到活跃会话: 用户{}, 资源类型{}, 资源ID{}", 
                         memberId, resourceType, resourceId);
                
                // 尝试直接更新数据库记录的完成状态
                studyRecordService.endStudyRecord(memberId, resourceType, resourceId, 
                                                  null, null, isComplete);
                
                log.info("结束学习记录(无会话): 用户{}, 资源类型{}, 资源ID{}, 仅更新完成状态{}", 
                         memberId, resourceType, resourceId, isComplete);
            }
        } catch (Exception e) {
            log.error("结束学习记录失败", e);
        }
    }
    
    /**
     * 启动自动保存任务
     * 
     * @param sessionKey 会话键
     */
    private static void startAutoSaveTask(String sessionKey) {
        scheduler.scheduleAtFixedRate(() -> {
            try {
                StudySession session = sessions.get(sessionKey);
                if (session == null) {
                    return; // 会话已结束，停止任务
                }
                
                // 计算增量时长并保存
                int durationIncrement = session.getDurationSinceLastSave();
                if (durationIncrement > 0) {
                    IDjStudyRecordService studyRecordService = SpringUtils.getBean(IDjStudyRecordService.class);
                    studyRecordService.updateStudyDuration(session.getMemberId(), 
                                                           session.getResourceType(), 
                                                           session.getResourceId(),
                                                           durationIncrement, 
                                                           session.getCurrentPosition());
                }
            } catch (Exception e) {
                log.error("自动保存学习进度失败: {}", sessionKey, e);
            }
        }, DEFAULT_SAVE_INTERVAL, DEFAULT_SAVE_INTERVAL, TimeUnit.SECONDS);
    }
    
    /**
     * 构建会话键
     */
    private static String buildSessionKey(Long memberId, String resourceType, Long resourceId) {
        return memberId + "_" + resourceType + "_" + resourceId;
    }
    
    /**
     * 获取当前活跃的学习会话数量
     */
    public static int getActiveSessionCount() {
        return sessions.size();
    }
    
    /**
     * 清理所有会话（通常在应用关闭时调用）
     */
    public static void clearAllSessions() {
        sessions.clear();
        scheduler.shutdown();
    }
} 